// BoundingFrustum.h
// 
/////////////////////////////////////////////////////////

#include "BoundingFrustum.hpp"

#define M(row,col)  matrix[col*4+row-5]

BoundingFrustum::BoundingFrustum(float *matrix)
{
    planes[NEARP].SetCoefficients(
        M(3, 1) + M(4, 1),
        M(3, 2) + M(4, 2),
        M(3, 3) + M(4, 3),
        M(3, 4) + M(4, 4));

    planes[FARP].SetCoefficients(
        -M(3, 1) + M(4, 1),
        -M(3, 2) + M(4, 2),
        -M(3, 3) + M(4, 3),
        -M(3, 4) + M(4, 4));

    planes[BOTTOM].SetCoefficients(
        M(2, 1) + M(4, 1),
        M(2, 2) + M(4, 2),
        M(2, 3) + M(4, 3),
        M(2, 4) + M(4, 4));

    planes[TOP].SetCoefficients(
        -M(2, 1) + M(4, 1),
        -M(2, 2) + M(4, 2),
        -M(2, 3) + M(4, 3),
        -M(2, 4) + M(4, 4));

    planes[LEFT].SetCoefficients(
        M(1, 1) + M(4, 1),
        M(1, 2) + M(4, 2),
        M(1, 3) + M(4, 3),
        M(1, 4) + M(4, 4));

    planes[RIGHT].SetCoefficients(
        -M(1, 1) + M(4, 1),
        -M(1, 2) + M(4, 2),
        -M(1, 3) + M(4, 3),
        -M(1, 4) + M(4, 4));

}

int BoundingFrustum::BoxInFrustum(AABB &box) {

    int result = INSIDE;
    int out;
    int in;

    // for each one of 6 planes
    for(int i=0; i < 6; i++) {
        // reset counters for corners in and out
        out = 0;
        in = 0;
        // for each corner of the box do ...
        // get out of the cycle as soon as a box as corners
        // both inside and out of the frustum
        for (int corner = 0; corner < 8 && (in==0 || out==0); corner++) {
            Vec3f point = box.GetPointAtCorner(corner);
            // is the corner outside or inside
             if (planes[i].Distance(point) < 0)
                out++;
            else
                in++;
        }
        // if all corners are out
        if (!in)
            return OUTSIDE;
        // if some corners are out and others are in
        else if (out)
            result = INTERSECT;
    }
    return result;
 }

#undef M
